import numpy as np
import cv2 # 4.2.0.32版本
from struct import unpack

# 代码参考:https://blog.csdn.net/rocketeerLi/article/details/84929516?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-1-84929516.nonecase#commentBox

class ReadBMPFile:
    def __init__(self, filePath):
        file = open(filePath, "rb")
        # 读取 bmp 文件的文件头    14 字节
        self.bfType = unpack("<h", file.read(2))[0]  # 0x4d42 对应BM 表示这是Windows支持的位图格式
        self.bfSize = unpack("<i", file.read(4))[0]  # 位图文件大小
        self.bfReserved1 = unpack("<h", file.read(2))[0]  # 保留字段 必须设为 0
        self.bfReserved2 = unpack("<h", file.read(2))[0]  # 保留字段 必须设为 0
        self.bfOffBits = unpack("<i", file.read(4))[0]  # 偏移量 从文件头到位图数据需偏移多少字节（位图信息头、调色板长度等不是固定的，这时就需要这个参数了）
        # 读取 bmp 文件的位图信息头 40 字节
        self.biSize = unpack("<i", file.read(4))[0]  # 所需要的字节数
        self.biWidth = unpack("<i", file.read(4))[0]  # 图像的宽度 单位 像素
        self.biHeight = unpack("<i", file.read(4))[0]  # 图像的高度 单位 像素
        self.biPlanes = unpack("<h", file.read(2))[0]  # 说明颜色平面数 总设为 1
        self.biBitCount = unpack("<h", file.read(2))[0]  # 说明比特数

        self.biCompression = unpack("<i", file.read(4))[0]  # 图像压缩的数据类型
        self.biSizeImage = unpack("<i", file.read(4))[0]  # 图像大小
        self.biXPelsPerMeter = unpack("<i", file.read(4))[0]  # 水平分辨率
        self.biYPelsPerMeter = unpack("<i", file.read(4))[0]  # 垂直分辨率
        self.biClrUsed = unpack("<i", file.read(4))[0]  # 实际使用的彩色表中的颜色索引数
        self.biClrImportant = unpack("<i", file.read(4))[0]  # 对图像显示有重要影响的颜色索引的数目
        self.bmp_data = []

        # 24位数据占3字节空间 读取[rgb]; 有的3字节内容存在4字节中
        if self.biBitCount == 24:
            for height in range(self.biHeight):
                bmp_data_row = []
                # 四字节填充位检测
                count = 0
                for width in range(self.biWidth):
                    bmp_data_row.append(
                        [unpack("<B", file.read(1))[0], unpack("<B", file.read(1))[0], unpack("<B", file.read(1))[0]])
                    count = count + 3
                # # bmp 四字节对齐原则
                # while count % 4 != 0:
                #     file.read(1)
                #     count = count + 1
                self.bmp_data.append(bmp_data_row)
            self.bmp_data.reverse()
            file.close()
            # R, G, B 三个通道
            self.R = []
            self.G = []
            self.B = []

            for row in range(self.biHeight):
                R_row = []
                G_row = []
                B_row = []
                for col in range(self.biWidth):
                    B_row.append(self.bmp_data[row][col][0])
                    G_row.append(self.bmp_data[row][col][1])
                    R_row.append(self.bmp_data[row][col][2])
                self.B.append(B_row)
                self.G.append(G_row)
                self.R.append(R_row)

        # 8字节单通道数据
        elif self.biBitCount == 8:
            # 略过调色板的数据,如果要实际应用,可能需要根据调色板修改像素值
            file.read(1024) # 手动计算,bmp大小占308,278字节,头文件占54字节,图片内容占640*480=307,200字节.因此调色板区域占1024字节

            for height in range(self.biHeight):
                bmp_data_row = []
                # 四字节填充位检测
                count = 0
                for width in range(self.biWidth):
                    bmp_data_row.append(unpack("<B", file.read(1))[0])
                    count = count + 1
                # bmp 四字节对齐原则
                # while count % 4 != 0:
                #     file.read(1)
                #     count = count + 1
                self.bmp_data.append(bmp_data_row)
            self.bmp_data.reverse()
            file.close()

# 24位三通道代码
def imshow_24(bmpFile, delay=0):
    R = bmpFile.R
    G = bmpFile.G
    B = bmpFile.B
    # 显示图像
    b = np.array(B, dtype=np.uint8)
    g = np.array(G, dtype=np.uint8)
    r = np.array(R, dtype=np.uint8)
    merged = cv2.merge([b, g, r])  # imread/imshow等都需要BGR顺序

    if delay != None:
        cv2.imshow("Merged", merged)
        cv2.waitKey(0)
    return merged

# 8位单通道代码
def imshow_8(bmpFile, delay=0):
    img = bmpFile.bmp_data
    Img = np.array(img, dtype=np.uint8)

    merged = cv2.merge([Img, Img, Img])  # 合并R、G、B分量 默认顺序为 B、G、R
    if delay != None:
        cv2.imshow("Merged", merged)
        cv2.waitKey(delay)
    return merged

# 代码测试用
# # 读取 BMP 文件
# bmpFile = ReadBMPFile("/home/ccc/桌面/bmp2jpg/imgs/000001.bmp")
# # imshow_24(bmpFile) # 24位三通道显示
# imshow_8(bmpFile) # 8位单通道显示

# 将list里的bmp转成jpg
def bmp2jpg():
    # ls imgs | sed "s:^:./imgs/:" >> list.txt
    list_road = "./list.txt"

    ii = 0
    with open(list_road, 'r', encoding='utf-8') as f:  # 只读
        for line in f:
            ii += 1
            line = line.strip('\n')
            bmp_name = line.strip().split("/")[-1]
            jpg_name = './jpg/' + bmp_name.strip().split(".")[0] + '.jpg'

            bmpFile = ReadBMPFile(line)
            if bmpFile.biBitCount == 8:
                jpg = imshow_8(bmpFile, delay=None)
            elif bmpFile.biBitCount == 24:
                jpg = imshow_24(bmpFile, delay=None)

            print(ii, bmp_name, jpg_name, jpg.shape)
            cv2.imwrite(jpg_name, jpg, [int(cv2.IMWRITE_JPEG_QUALITY)])


if __name__=="__main__":
    bmp2jpg()

